package jstudy.gu.kit.string;

import java.util.*;
import java.util.stream.Stream;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.core.json.JsonReadFeature;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.type.CollectionType;

import lombok.SneakyThrows;

/**
 * @author guweichao
 * @created 2019年6月28日
 * @desc json相关工具集
 */
public class JsonKit {
	private final static String lineSeparator = System.lineSeparator();
	private static ThreadLocal<ObjectMapper> mapper = ThreadLocal
			.withInitial(() -> JsonMapper.builder().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
					.enable(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS).build()
					.setSerializationInclusion(Include.NON_EMPTY));

	@SneakyThrows
	public static String toJson(Object obj) {
		return mapper.get().writeValueAsString(obj);
	}

	@SneakyThrows
	public static <T> T toBean(String json, Class<T> clz) {
		return mapper.get().readValue(json, clz);
	}

	/**
	 * @author guweichao
	 * @created_at 2020-8-31 16:29:08
	 * @param json 获取tree 模型, 便于取中间少量数据,配合treeToValue
	 * @return
	 * @see treeToValue
	 */
	@SneakyThrows
	public static JsonNode getTree(String json) {
		return mapper.get().readTree(json);
	}

	/**
	 * @author guweichao 将tree 模型转为实体对象
	 * @created_at 2020-8-31 16:29:39
	 * @param <T>
	 * @param json
	 * @param clz
	 * @return
	 * @see getTree
	 */
	@SneakyThrows
	public static <T> T treeToValue(TreeNode json, Class<T> clz) {
		return mapper.get().treeToValue(json, clz);
	}

	@SneakyThrows
	public static <T> List<T> toBeanList(String json) {
		return mapper.get().readValue(json, new TypeReference<List<T>>() {
		});
	}

	@SneakyThrows
	public static <T> List<T> toBeanList(Stream<String> jsons, Class<T> clz) {
		List<T> rl;
		if (jsons == null) {
			rl = new ArrayList<>();
		} else {
			rl = new LinkedList<>();
			String[] ll = { "" };
			jsons.forEach(ijson -> {
				String lastline = ll[0];
				if (ijson != null && ijson.length() != 0) {
					if (lastline.isEmpty()) {
						if (ijson.charAt(0) == '{') {
							lastline = ijson;
						}
					} else {
						lastline = lastline + lineSeparator + ijson;
					}
					if (!lastline.isEmpty()) {
						if (!lastline.isEmpty()) {
							if (lastline.charAt(lastline.length() - 1) == '}') {
								rl.add(toBean(lastline, clz));
								lastline = "";
							}
						}
					}
				}
			});
		}
		return rl;
	}

	@SneakyThrows
	public static <T> List<T> toBeanList(Collection<String> jsons, Class<T> clz) {
		List<T> rlist;
		if (jsons == null || jsons.isEmpty()) {
			rlist = new ArrayList<>();
		} else {
			rlist = toBeanList(jsons.stream(), clz);
		}
		return rlist;
	}

	@SneakyThrows
	public static <T> List<T> toBeanListIgnoreErrorLine(Collection<String> jsons, Class<T> clz) {
		List<T> rlist;
		if (jsons == null || jsons.isEmpty()) {
			rlist = new ArrayList<>();
		} else {
			rlist = toBeanListIgnoreErrorLine(jsons.stream(), clz);
		}
		return rlist;
	}

	/**
	 * @author guweichao json 转为 对象，忽略其中错误行，其余继续解析
	 * @created_at 2020-6-26 16:12:50
	 * @param <T>
	 * @param jsons
	 * @param clz
	 * @return
	 */
	@SneakyThrows
	public static <T> List<T> toBeanListIgnoreErrorLine(Stream<String> jsons, Class<T> clz) {
		List<T> rl;
		if (jsons == null) {
			rl = new ArrayList<>();
		} else {
			rl = new LinkedList<>();
			String[] ll = { "" };
			jsons.forEach(ijson -> {
				String lastline = ll[0];
				if (ijson != null && ijson.length() != 0) {
					if (lastline.isEmpty()) {
						if (ijson.charAt(0) == '{') {
							lastline = ijson;
						}
					} else {
						lastline = lastline + lineSeparator + ijson;
					}
					if (!lastline.isEmpty()) {
						if (!lastline.isEmpty()) {
							if (lastline.charAt(lastline.length() - 1) == '}') {
								try {
									T bean = toBean(lastline, clz);
									rl.add(bean);
								} catch (Exception e) {
									System.err.println("json 格式错误:" + lastline);
									e.printStackTrace();
								}
								lastline = "";
							}
						}
					}
				}
			});
		}
		return rl;
	}

	@SneakyThrows
	public static <T> List<T> toBeanList(String json, Class<T> clz) {
		ObjectMapper objectMapper = mapper.get();
		CollectionType javaType = objectMapper.getTypeFactory().constructCollectionType(List.class, clz);
		return objectMapper.readValue(json, javaType);
	}

}
